x86: Improve zap_low_mappings.
authorKeir Fraser <keir@xensource.com>
Sat, 12 May 2007 11:07:01 +0000 (12:07 +0100)
committerKeir Fraser <keir@xensource.com>
Sat, 12 May 2007 11:07:01 +0000 (12:07 +0100)
Do it earlier on x86/64, properly free non-superpages on x86/32, and
leave a mapping of the boot trampoline (0x90000-0xA0000) in place.

Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/domain_build.c
xen/arch/x86/mm.c
xen/arch/x86/setup.c
xen/arch/x86/smpboot.c
xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_64/mm.c
xen/include/asm-x86/page.h

index 3f491b5f7c90209e598523ba0a2ac4bfbb6fd5d7..dffa7ce3459e82a68adaa697b6be2e877ea58e0c 100644 (file)
@@ -902,7 +902,6 @@ int __init construct_dom0(
 #if defined(__i386__)
     /* Destroy low mappings - they were only for our convenience. */
     zap_low_mappings(l2start);
-    zap_low_mappings(idle_pg_table_l2);
 #endif
 
     update_domain_wallclock_time(d);
index 5e15ab13b0b3585013d89ea092fa29d2b1c6ba12..9c57c2e725f16c7c962d95b3858d8ad06198d700 100644 (file)
@@ -3402,6 +3402,18 @@ int ptwr_do_page_fault(struct vcpu *v, unsigned long addr,
     return 0;
 }
 
+void free_xen_pagetable(void *v)
+{
+    extern int early_boot;
+
+    BUG_ON(early_boot);
+    
+    if ( is_xen_heap_frame(virt_to_page(v)) )
+        free_xenheap_page(v);
+    else
+        free_domheap_page(virt_to_page(v));
+}
+
 int map_pages_to_xen(
     unsigned long virt,
     unsigned long mfn,
@@ -3475,6 +3487,73 @@ int map_pages_to_xen(
     return 0;
 }
 
+void destroy_xen_mappings(unsigned long s, unsigned long e)
+{
+    l2_pgentry_t *pl2e;
+    l1_pgentry_t *pl1e;
+    unsigned int  i;
+    unsigned long v = s;
+
+    ASSERT((s & ~PAGE_MASK) == 0);
+    ASSERT((e & ~PAGE_MASK) == 0);
+
+    while ( v < e )
+    {
+        pl2e = virt_to_xen_l2e(v);
+
+        if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) )
+        {
+            v += PAGE_SIZE;
+            continue;
+        }
+
+        if ( l2e_get_flags(*pl2e) & _PAGE_PSE )
+        {
+            if ( (l1_table_offset(v) == 0) &&
+                 ((e-v) >= (1UL << L2_PAGETABLE_SHIFT)) )
+            {
+                /* PSE: whole superpage is destroyed. */
+                l2e_write_atomic(pl2e, l2e_empty());
+                v += 1UL << L2_PAGETABLE_SHIFT;
+            }
+            else
+            {
+                /* PSE: shatter the superpage and try again. */
+                pl1e = alloc_xen_pagetable();
+                for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
+                    l1e_write(&pl1e[i],
+                              l1e_from_pfn(l2e_get_pfn(*pl2e) + i,
+                                           l2e_get_flags(*pl2e) & ~_PAGE_PSE));
+                l2e_write_atomic(pl2e, l2e_from_pfn(virt_to_mfn(pl1e),
+                                                    __PAGE_HYPERVISOR));
+            }
+        }
+        else
+        {
+            /* Ordinary 4kB mapping. */
+            pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(v);
+            l1e_write_atomic(pl1e, l1e_empty());
+            v += PAGE_SIZE;
+
+            /* If we are done with the L2E, check if it is now empty. */
+            if ( (v != e) && (l1_table_offset(v) != 0) )
+                continue;
+            pl1e = l2e_to_l1e(*pl2e);
+            for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ )
+                if ( l1e_get_intpte(pl1e[i]) != 0 )
+                    break;
+            if ( i == L1_PAGETABLE_ENTRIES )
+            {
+                /* Empty: zap the L2E and free the L1 page. */
+                l2e_write_atomic(pl2e, l2e_empty());
+                free_xen_pagetable(pl1e);
+            }
+        }
+    }
+
+    flush_tlb_all_pge();
+}
+
 void __set_fixmap(
     enum fixed_addresses idx, unsigned long mfn, unsigned long flags)
 {
index 09c81d98b9565ad42d41270c0b98dce5f2fe8aa1..fdf04ae9a86a6920a6c1a940632882213c30b08d 100644 (file)
@@ -779,6 +779,11 @@ void __init __start_xen(multiboot_info_t *mbi)
     if ( smp_found_config )
         get_smp_config();
 
+#ifdef CONFIG_X86_64
+    /* Low mappings were only needed for some BIOS table parsing. */
+    zap_low_mappings();
+#endif
+
     init_apic_mappings();
 
     init_IRQ();
index f878874d69ad6ec9e1013e739d112a892b656ca9..1e8af577d33d6611767ac023e7aa0e06ec30c901 100644 (file)
@@ -1162,9 +1162,6 @@ void __init smp_cpus_done(unsigned int max_cpus)
 #ifdef CONFIG_X86_IO_APIC
        setup_ioapic_dest();
 #endif
-#ifdef CONFIG_X86_64
-       zap_low_mappings();
-#endif
 #ifndef CONFIG_HOTPLUG_CPU
        /*
         * Disable executability of the SMP trampoline:
index 29620a36ce2841b708bb452c5b3d1573de3b58ec..eab7e1be724d042afcd747a95089f8a201acfcae 100644 (file)
@@ -61,11 +61,6 @@ void *alloc_xen_pagetable(void)
     return mfn_to_virt(mfn);
 }
 
-void free_xen_pagetable(void *v)
-{
-    free_xenheap_page(v);
-}
-
 l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
 {
     return &idle_pg_table_l2[l2_linear_offset(v)];
@@ -141,22 +136,24 @@ void __init setup_idle_pagetable(void)
                                 __PAGE_HYPERVISOR));
 }
 
-void __init zap_low_mappings(l2_pgentry_t *base)
+void __init zap_low_mappings(l2_pgentry_t *dom0_l2)
 {
     int i;
-    u32 addr;
 
-    for ( i = 0; ; i++ )
-    {
-        addr = i << L2_PAGETABLE_SHIFT;
-        if ( addr >= HYPERVISOR_VIRT_START )
-            break;
-        if ( l2e_get_paddr(base[i]) != addr )
-            continue;
-        l2e_write(&base[i], l2e_empty());
-    }
+    /* Clear temporary idle mappings from the dom0 initial l2. */
+    for ( i = 0; i < (HYPERVISOR_VIRT_START >> L2_PAGETABLE_SHIFT); i++ )
+        if ( l2e_get_intpte(dom0_l2[i]) ==
+             l2e_get_intpte(idle_pg_table_l2[i]) )
+            l2e_write(&dom0_l2[i], l2e_empty());
+
+    /* Now zap mappings in the idle pagetables. */
+    destroy_xen_mappings(0, HYPERVISOR_VIRT_START);
 
     flush_tlb_all_pge();
+
+    /* Replace with mapping of the boot trampoline only. */
+    map_pages_to_xen(BOOT_TRAMPOLINE, BOOT_TRAMPOLINE >> PAGE_SHIFT,
+                     0x10, __PAGE_HYPERVISOR);
 }
 
 void __init subarch_init_memory(void)
index e5b6267f2c821b14c4e78b5f2454891e065bb6d3..444432f13645cc96edf2022589d5b40b10c96938 100644 (file)
@@ -70,11 +70,6 @@ void *alloc_xen_pagetable(void)
     return mfn_to_virt(mfn);
 }
 
-void free_xen_pagetable(void *v)
-{
-    free_domheap_page(virt_to_page(v));
-}
-
 l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
 {
     l4_pgentry_t *pl4e;
@@ -209,8 +204,15 @@ void __init setup_idle_pagetable(void)
 
 void __init zap_low_mappings(void)
 {
+    BUG_ON(num_online_cpus() != 1);
+
+    /* Remove aliased mapping of first 1:1 PML4 entry. */
     l4e_write(&idle_pg_table[0], l4e_empty());
-    flush_tlb_all_pge();
+    local_flush_tlb_pge();
+
+    /* Replace with mapping of the boot trampoline only. */
+    map_pages_to_xen(BOOT_TRAMPOLINE, BOOT_TRAMPOLINE >> PAGE_SHIFT,
+                     0x10, __PAGE_HYPERVISOR);
 }
 
 void __init subarch_init_memory(void)
index 36fe4a5e74c84170cc254b7fac51afba166c1955..681da219a36d78c1b22439412dec8e85199e7740 100644 (file)
@@ -1,4 +1,3 @@
-
 #ifndef __X86_PAGE_H__
 #define __X86_PAGE_H__
 
@@ -369,6 +368,7 @@ map_pages_to_xen(
     unsigned long mfn,
     unsigned long nr_mfns,
     unsigned long flags);
+void destroy_xen_mappings(unsigned long v, unsigned long e);
 
 #endif /* !__ASSEMBLY__ */